Repository navigation
feat: lightweight static render for non-animated mobile charts (+ ReferenceLine strokeWidth) - #840
Merged
hcopp merged 3 commits intoAug 11, 2026
Conversation
Collaborator
✅ Heimdall Review Status
✅
|
| Code Owner | Status | Calculation | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| ui-systems-eng-team |
✅
1/1
|
Denominator calculation
|
alfonsocj
marked this pull request as ready for review
August 11, 2026 16:11
hcopp
reviewed
Aug 11, 2026
hcopp
reviewed
Aug 11, 2026
hcopp
reviewed
Aug 11, 2026
hcopp
reviewed
Aug 11, 2026
hcopp
reviewed
Aug 11, 2026
hcopp
reviewed
Aug 11, 2026
alfonsocj
force-pushed
the
mux/add-sparkline-lightweight-mode
branch
from
August 11, 2026 17:42
bdc04fe to
ee78184
Compare
Adds `interactive?: boolean` (default true) to cds-mobile CartesianChart
(inherited by LineChart). `interactive={false}` skips the scrubber context and
entrance animation and renders lines via a reanimated-free static Path that
clips with a cheap rect (canvas.clipRect) instead of the anti-aliased path clip,
cutting the main-thread SoftwarePathRenderer cost when many charts recycle in
scrolling lists. Additive and backward-compatible (default preserves behavior).
Linear: APP-770
Co-Authored-By: Claude <noreply@anthropic.com>
…rubberProvider
- Remove the `interactive` prop; the lightweight static render now rides on the existing
`animate={false}` (Path routes to a reanimated-free StaticChartPath with a cheap rect clip).
- ScrubberProvider skips the pan gesture + animated reaction when scrubbing is disabled.
- Add a `strokeWidth` prop to ReferenceLine; narrow StaticChartPath props (review nit).
- Update docs, story (animate={false}), and tests; add ScrubberProvider test.
- Bump @coinbase/cds-mobile to 9.13.0 (+ release sync).
Linear: APP-770
Co-Authored-By: Claude <noreply@anthropic.com>
- ScrubberProvider: enabled provider no longer branches on enableScrubbing (always on). - Path: static path uses useDerivedValue so an animated d (e.g. reference lines) tracks scrubbing. - Trim verbose JSDoc/comments per review. Co-Authored-By: Claude <noreply@anthropic.com>
alfonsocj
force-pushed
the
mux/add-sparkline-lightweight-mode
branch
from
August 11, 2026 17:51
ee78184 to
1c2c9e4
Compare
hcopp
approved these changes
Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed? Why?
Makes the CDS cds-mobile chart render a lightweight, static line when it isn't animating — with no new public API. The win rides on the existing
animateprop plus an internalScrubberProvideroptimization:Pathstatic branch (the clip win).Pathnow delegates to a reanimated-freeStaticChartPathwhen the chart isn't animating (animate={false}, which is also what non-interactive charts want). It clips with an axis-aligned rect (routed tocanvas.clipRect, a GPU scissor) instead of the anti-aliased path clip (Skia.Path.addRect()→canvas.clipPath) that falls back to Skia's CPUSoftwarePathRenderer. The animated branch is unchanged.ScrubberProvider(the scrubber win). WhenenableScrubbingis false (the default), the provider now skips the pan gesture and theuseAnimatedReactionallocation entirely (split into enabled/disabled providers). Every non-scrubbing chart benefits, not just a special mode.ReferenceLinestrokeWidth. New prop so callers can size the reference line (previously fixed at the line component's default).Why: non-interactive row sparklines in scrolling lists pay a main-thread Skia cost from the anti-aliased path clip when many rows recycle.
consumer/react-native#73650 worked around it with a bespokeLightweightSparkline; per the reviewer's comment the clean long-term fix is a static mode on the CDS chart so callers get the win without a bespoke component. This delivers that via existing props.Consumer migration (follow-up PR, after release): replace
<LightweightSparkline …/>with<LineChart animate={false} …>+<ReferenceLine dataY={…} />, then delete the bespoke component.Linear: https://linear.app/coinbase/issue/APP-770
Root cause (required for bugfixes)
N/A — performance feature, not a bugfix. (The cost is the anti-aliased path clip →
SoftwarePathRenderer; a rect clip is a GPU scissor and preserves bounds, socurve="bump"overshoot cannot bleed out.)UI changes
No visible change to animated (default) usage — the animated render path is untouched.
animate={false}renders the line identically at rest (the rect clip preserves the same bounds as the previous path clip); it only drops the entrance-reveal animation. A new "Lightweight (Static)"LineChartstory variant was added (data crossing a dottedReferenceLine) so the mobile visreg target (apps/expo-app) captures it.Captured on the iOS simulator and Android emulator running the new "Lightweight (Static)"
LineChartstory (animate={false}); visual parity is also covered by the story + visreg.Testing
How has it been tested?
Testing instructions
chart/__tests__/Path.test.tsx: asserts the static branch clips with a rect (canvas.clipRect) not an SkPath, honors an explicitclipPath, and that the animated path is still used when the chart animates.chart/scrubber/__tests__/ScrubberProvider.test.tsx: asserts the pan gesture +useAnimatedReactionare set up whenenableScrubbingis true and skipped when it's false.chart/line/__tests__/LineChart.test.tsx: smoke-renders ananimate={false}chart.typecheck,lint(0 errors),formatall pass.Residual / follow-up (not addressed here): in the static case
useChartLayout's rAF measure→setState double render and the full scale/domain recompute still run, so this is lighter than the bareLightweightSparklinebut not equivalent.consumer/react-nativeshould confirm with a native trace before removing its kill switch.Illustrations/Icons Checklist
N/A — no changes under
packages/illustrations/**orpackages/icons/**.Change management
type=routine
risk=low
impact=sev5
automerge=false